using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using CodePlex.SpaceBlock.FS;
using CodePlex.Resourceful;
using CodePlex.Resourceful.Amazon.S3;
using System.Net;

namespace CodePlex.SpaceBlock.UI.Controls.Explore
{
    public partial class ServerAccessLogViewerForm : BaseForm
    {


        private BindingSourceFilterManager _filterManager;

        private S3FileSystem _s3fs;
        private List<Path> _selectedPaths;

        private BindingSource _bindingSource;
        private DataTable _data;
        private bool _closed;


        public ServerAccessLogViewerForm()
        {
            InitializeComponent();

            this.Text = "Analyze Server Access Logs";

            this.WindowState = FormWindowState.Maximized;

            _grid.SelectionMode = DataGridViewSelectionMode.CellSelect;
            _grid.ReadOnly = true;
            _grid.AllowUserToAddRows = false;
            _grid.AllowUserToDeleteRows = false;
            

            _grid.Columns.Clear();

            _grid.ColumnAdded += delegate(object sender, DataGridViewColumnEventArgs e)
            {
                e.Column.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
                e.Column.SortMode = DataGridViewColumnSortMode.Automatic;
            };


            this.SetupActions();

            this.FormClosed += delegate
            {
                _closed = true;
            };


        }



        private void SetupActions()
        {
            ContextMenuStrip contextMenu = new ContextMenuStrip();

            ActionManager actions = new ActionManager(this, UIManager.Instance.SmallImageList, contextMenu, null);

            actions.NewAction("HideColumn", "Hide Column", -1, null, delegate
            {
                int c = _grid.SelectedCells[0].ColumnIndex;
                _grid.Columns[c].Visible = false;

            });


            actions.NewSeparator("sep");
           

            actions.NewAction("Exclude", "Exclude in filter", -1, null, delegate
            {
                foreach (DataGridViewCell cell in _grid.SelectedCells)
                {
                    string name = _grid.Columns[cell.ColumnIndex].Name;
                    object value = cell.Value;
                    _filterManager.AddExclude(name,value);
                }
                UpdateStatus();
            });



            actions.NewAction("Include", "Include in filter", -1, null, delegate
           {
               foreach (DataGridViewCell cell in _grid.SelectedCells)
               {
                   string name = _grid.Columns[cell.ColumnIndex].Name;
                   object value = cell.Value;
                   _filterManager.AddInclude(name, value);
               }
               UpdateStatus();
           });
            actions.NewAction("Clear", "Clear filter", -1, null, delegate
            {
                _filterManager.Clear();
                UpdateStatus();
            });




            actions.BindTo(_grid);
        }


      

      


        private void _okButton_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        
        
        public void Initialize(S3FileSystem s3fs, List<Path> selectedPaths)
        {
            _s3fs = s3fs;
            _selectedPaths = selectedPaths;


            _data = new DataTable();
            TypedLogRecord.AddDataTableColumns(_data);


            _bindingSource = new BindingSource();
            _bindingSource.DataSource = _data;
            _filterManager = new BindingSourceFilterManager(_bindingSource);
            
            _grid.DataSource = _bindingSource;


            _grid.Columns["BytesSent"].CellTemplate.Style.Alignment = DataGridViewContentAlignment.MiddleRight;
            _grid.Columns["BytesSent"].CellTemplate.Style.Format = "n0";
            _grid.Columns["ObjectSize"].CellTemplate.Style.Alignment = DataGridViewContentAlignment.MiddleRight;
            _grid.Columns["ObjectSize"].CellTemplate.Style.Format = "n0";

            _grid.Sort(_grid.Columns["Time"], ListSortDirection.Descending);


            this.UpdateStatus();
            
            this.Load += delegate
            {
                this.InBackground(delegate
                {
                    string bucket = _s3fs.ToBucketKey(_selectedPaths[0]).Value1;
                    IEnumerable<string> keys = _selectedPaths.ConvertAll<string>(delegate(Path item) 
                    {
                        return _s3fs.ToBucketKey(item).Value2;
                    });


                    IEnumerable<LogRecord> records =  s3fs.S3Connection.GetLogRecords(bucket, keys);


                    foreach (List<LogRecord> recordsList in Utils.Batch(records, 100))
                    {
                        if (_closed)
                        {
                            return;
                        }
                        this.InDisplay(delegate
                        {


                          //  _grid.ClearSelection();

                            //int? x = null, y = null;
                            //if (_grid.SelectedCells.Count > 0)
                            //{
                            //    x = _grid.SelectedCells[0].ColumnIndex;
                            //    y = _grid.SelectedCells[0].RowIndex;
                            //}

                            _data.BeginLoadData();
                            foreach (LogRecord record in recordsList)
                            {
                                TypedLogRecord tlr = new TypedLogRecord(record);
                                _data.LoadDataRow(tlr.ToDataRow(),true);
                               
                                //_dataSource.Add(new TypedLogRecord(record));
                            }
                            _data.EndLoadData();
                            UpdateStatus();

                            //_grid.ClearSelection();
                            //if (x.HasValue)
                            //{
                                
                            //    _grid.Rows[y.Value].Cells[x.Value].Selected = true;
                            //}


                        });
                    }



                });
            };

        }


        private void UpdateStatus()
        {
            _status.Text = string.Format("Showing {0} of {1} rows.  Filter: {2}",
                             _grid.Rows.Count,
                             _data.Rows.Count,
                             _bindingSource.Filter==null?"(none)":_bindingSource.Filter);
        }


      
        

        
    }










    public class TypedLogRecord
    {
        private readonly LogRecord _record;


        private readonly IPAddress _remoteIP;
        private readonly long _bytesSent;
        private readonly long _objectSize;
        private readonly TimeSpan _totalTime;
        private readonly TimeSpan _turnaroundTime;
        private readonly DateTime _time;
        private readonly int _httpStatus;

        public TypedLogRecord(LogRecord record)
        {
            _record = record;

            _time = DateTime.SpecifyKind(DateTime.ParseExact(_record.Time.Substring(0, 20), @"dd\/MMM\/yyyy:HH:mm:ss", null), DateTimeKind.Utc)
                        .ToLocalTime();
            _remoteIP = IPAddress.Parse(_record.RemoteIP);
            _bytesSent = 0; long.TryParse(_record.BytesSent, out _bytesSent);
            _objectSize = 0; long.TryParse(_record.ObjectSize, out _objectSize);
            _totalTime = TimeSpan.FromMilliseconds(double.Parse(_record.TotalTime));
            double tat = 0; double.TryParse(_record.TurnAroundTime, out tat);
            _turnaroundTime = TimeSpan.FromMilliseconds(tat);
            _httpStatus = int.Parse(_record.HTTPStatus);


        }

        public string BucketOwner { get { return _record.BucketOwner; } }
        public string Bucket { get { return _record.Bucket; } }
        public DateTime Time { get { return _time; } }
        public IPAddress RemoteIP { get { return _remoteIP; } }
        public string Requestor { get { return _record.Requestor; } }
        public string RequestID { get { return _record.RequestID; } }
        public string Operation { get { return _record.Operation; } }
        public string Key { get { return _record.Key; } }
        public string RequestURI { get { return _record.RequestURI; } }
        public int HTTPStatus { get { return _httpStatus; } }
        public string ErrorCode { get { return _record.ErrorCode; } }
        public long BytesSent { get { return _bytesSent; } }
        public long ObjectSize { get { return _objectSize; } }
        public TimeSpan TotalTime { get { return _totalTime; } }
        public TimeSpan TurnAroundTime { get { return _turnaroundTime; } }
        public string Referrer { get { return _record.Referrer; } } 
        public string UserAgent { get { return _record.UserAgent; } }



        public static void AddDataTableColumns(DataTable table) 
        {
            table.Columns.Add("BucketOwner", typeof(string));
            table.Columns.Add("Bucket", typeof(string));
            table.Columns.Add("Time", typeof(DateTime));
            table.Columns.Add("RemoteIP", typeof(string));
            table.Columns.Add("Requestor", typeof(string));
            table.Columns.Add("RequestID", typeof(string));
            table.Columns.Add("Operation", typeof(string));
            table.Columns.Add("Key", typeof(string));
            table.Columns.Add("RequestURI", typeof(string));
            table.Columns.Add("HTTPStatus", typeof(int));
            table.Columns.Add("ErrorCode", typeof(string));
            table.Columns.Add("BytesSent", typeof(long));
            table.Columns.Add("ObjectSize", typeof(long));
            table.Columns.Add("TotalTime", typeof(TimeSpan));
            table.Columns.Add("TurnAroundTime", typeof(TimeSpan));
            table.Columns.Add("Referrer", typeof(string));
            table.Columns.Add("UserAgent", typeof(string));
        }


        public object[] ToDataRow()
        {
            return new object[]{
                        this.BucketOwner,
                         this.Bucket,
                         this.Time,
                         this.RemoteIP,
                         this.Requestor,
                         this.RequestID,
                         this.Operation,
                         this.Key,
                         this.RequestURI,
                         this.HTTPStatus,
                         this.ErrorCode,
                         this.BytesSent,
                         this.ObjectSize,
                         this.TotalTime,
                         this.TurnAroundTime,
                         this.Referrer,
                         this.UserAgent
            };

        }

    }



  









}